; findncall.asm by lucaze_b and lebrun_b
; This part of code find the api function wanted
; by searching in the export tables
; and jmp to it to preserve the original caller
; 

FindNCall:
    assume fs:NOTHING                           ; unset ERROR
    pushad                                      ; save registers
    mov ebp,esp                                 ; Create a new stack frame
    xor edx,edx
    mov edx,fs:[edx+48]                         ; edx = pointer to the PEB
    mov edx,[edx+12]                            ; edx = PEB->Ldr
    mov edx,[edx+20]                            ; edx = first module of the module list
    
_nextMod:
    mov esi,[edx+40]                            ; esi = pointer to modules name
    movzx ecx,WORD ptr [edx+38]                 ; ecx = length of module name
    xor edi,edi

_hashmodLoop:
    xor eax,eax
    lodsb                                       ; Read the next byte of the name
    cmp al,'a'                                  ; If current character is uppercase
    jl _rotate                                  ;   jmp to _rotate
    sub al,20h                                  ; Else sub 32 to get uppercase char
    
_rotate:
    ror edi,13                                  ; Rotate right our hash value
    add edi,eax                                 ; Add the next byte of the name
    loop _hashmodLoop                           ; Loop untill we have read enough (while ecx != 0)
    push edx                                    ; Save current position in the module list
    push edi                                    ; Save current module hash

_iterateExporteTable:
    mov edx,[edx+16]                            ; edx = current module base address
    mov eax,[edx+60]                            ; eax = PE header offset
    add eax,edx                                 ; eax = PE header offset + module base address
    mov eax,[eax+120]                           ; eax = Export tables rva
    test eax,eax                                ; If no Export address table
    jz _getNextMod1                             ;   process with next module
    add eax,edx                                 ; eax = Export tables va
    push eax                                    ; Save Export tables address
    mov ecx,[eax+24]                            ; ecx = number of function names
    mov ebx,[eax+32]                            ; ebx = function name rva
    add ebx,edx                                 ; ebx = function name va

_getNextFunc:
    jecxz _getNextMod                           ; If ecx = 0 Then jmp to _get_next_mod
    dec ecx                                     ; Decrement function name counter
    mov esi,[ebx+ecx*4]                         ; esi = next function name rva
    add esi,edx                                 ; esi = next function name va
    xor edi,edi
  
_funcnameLoop:
    xor eax,eax
    lodsb                                       ; Read the next byte of function name
    ror edi,13                                  ; Rotate right our hash value
    add edi,eax                                 ; Add the next byte of the name
    cmp al,0h                                   ; If next byte of the name != '\0'
    jne _funcnameLoop                           ;   Continue hashing name
    add edi,[ebp-8]                             ; edi = function hash + current module hash
    cmp edi,[ebp+36]                            ; Compare obtained hash to the hash passed in argument (on the stack)
    jnz _getNextFunc                            ; If not equals, proceed with next function name
  
_getFuncAddr:
    pop eax                                     ; eax = current module Export Address Table
    mov ebx,[eax+36]                            ; ebx = Ordinal table rva
    add ebx,edx                                 ; ebx = Ordinal table va
    mov cx,[ebx+2*ecx]                          ; ecx = wanted function ordinal
    mov ebx,[eax+28]                            ; ebx = function addresses table rva
    add ebx,edx                                 ; ebx = function addresses table va
    mov eax,[ebx+4*ecx]                         ; eax = wanted function rva
    add eax,edx                                 ; eax = wanted function va
  
_cleanStack:
    pop ebx                                     ; pop current module hash
    pop ebx                                     ; pop current position in the module list
    mov [esp+28],eax                            ; Overwrite the old EAX value with the desired api address for the upcoming popad
    popad                                       ; Restore registers
    pop ecx                                     ; ecx = origional return address
    pop edx                                     ; pop the hash value
    push ecx                                    ; push origional return address
    jmp eax                                     ; Jump into the wanted function

_getNextMod:
    pop eax                                     ; Pop previous module Export Address Table
  
_getNextMod1:
    pop edi                                     ; Pop previous module hash
    pop edx                                     ; Restore position in the module list
    mov edx,[edx]                               ; Get the next module
    jmp _nextMod                                ; Process with next module
